Creating components at run-time


Delphi is a visual design tool, so that you can drop components and configure it
by mouse without writing any code. Some times you need to create unknown number of
components which may depends on run-time event or user choice, for example you want
to create Memo components according to the number of text files that exists in "My
Documents" folder, if files there is a 10 text file there you want to create 10 Memos,
if files is 20 you want to create 20 Memos. Doing so can't be possible at design
time, at design time you have to know exact number of components you want. The best
way to solve such problems is to create Memos at run-time.

Creating components at run-time is a very easy task, the all thing you have to do
is to declare an object of component class such as:

var
MyButton: TButton;

After that you have to create new component using class's Create constructor such
as:

 MyButton:= TButton.Create(Self);

In this case Create constructor needs one parameter which called Owner. Owner is
the component which will owns new created object, such as forms and panels. If a
form or a panel owns a component, this component will be destroyed if it's owner
(Form or Panel) is destroyed. If you assign Nil value to owner parameter that mean
you have to free this component your self using
Free method befor your application
terminated such as:

 MyButton.Free;

Example


- Add
StdCtrls to uses clause
- On Form's
OnMouseUp event write:

var
MyButton: TButton;
begin
MyButton:= TButton.
Create(Self);
MyButton.
Parent:= Self;
MyButton.Left:= X;
MyButton.Top:= Y;
MyButton.Caption:= 'Button # '+
  IntToStr(Random(1000));

- Run the application then click mouse button in diffefent places at form.

New created button can be designed as any design time buttons: you can position
it, resize it, change it's caption, and so on... but how can you write event procedure
on it, for example how can you write OnClick event for run time components ?

Event procedures

You can write event procedures at design time to be linked later at rum time when
components created.
To clarify this concept suppose that we want to write an OnClick event for new created
buttons, simply you can write this procedure at form's unit:

procedure TForm1.MyOnClick(Sender: TObject);
begin
ShowMessage(TButton(Sender).Caption);
end;

Notice that this event is not a normal procedure, it must be a method of the form
by adding (
TForm1) class name. Second important thing is the procedure parameters,
it must by the exact OnClick event procedure (
Sender: TObject), you can not add or
ignore some procedures event parameters. When you write any method to the form, you
have to include it's header in form's class declaration at the top part of form's
unit, at Interface section, you can write it in private or public section:

type
TForm1 = class(TForm)


Header will be:

 public

 procedure MyOnClick(Sender: TObject);

Complete form declaration should be:

type
TForm1 = class(TForm)
  procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);
private
  { Private declarations }
public
 
procedure MyOnClick(Sender: TObject);
  { Public declarations }
end;

Now you write an OnClick event procedure for a button, but how can you link it with
created button's ?

The answer is very simple, all you have to do is to write below statement at button
creation procedure:

 MyButton.OnClick:= MyOnClick;

The complete procedure should be:

var
MyButton: TButton;
begin
MyButton:= TButton.Create(nil);
MyButton.Parent:= Form1;
MyButton.Left:= X;
MyButton.Top:= Y;
MyButton.Caption:= 'Button # '+IntToStr(Random(1000));
 MyButton.OnClick:= MyOnClick;


Common mistake on creating components at run time

If you create new component such as a Button and assign to it an owner like a Form,
this owner (Form) will ensures that it will free new created button befor it was
destroyed (the form), so that no need for freeing the Button manually. If you did
(Free the button manually) this will confuse the form and may generates access violation
error when the form attempts to free already destroyed buttons.

Notes:

- Some Delphi objects cann't be created at design time such as TRegistry, and TStringList,
so that you have to create them at run time and free them befor application is terminated
or after finishing using them.

- If you create a component or an object at run time and you do not specify an owner
to it, or it cann't be assigned to owner such as TStringList; be sure to free it
befor your application is terminated or after you finish using it, for example you
can write statements like this on main form's OnClose event or at the bottom of procedure
in which you use that objects:

MyList.
Free;
MyRegs.
Free;